#ifndef VL_FILE__H_
#define VL_FILE__H_

#include <string>
#include <cstdlib>
#include <fstream>
#include <vector>
#include <cstdint>
#include <memory>

/**
 * +======================================================================================================================+
 * @Author: CimZzz
 * @Date: 2022-02-11 16:02:17
 * 
 * 代码分割块，以下内容涉及: 
 * 
 * 宏定义区分系统特性
 * 
 */
#if defined _WIN32 || defined _WIN64
	// Windows 系统
	#define FILE_SEPERATOR '\\' // 文件分割符
	#include <Windows.h>
	#include <io.h>
	#include <sys/stat.h>
	#include <sys/types.h>
	#define stat _stat
#elif defined __APPLE__ || defined __MACH__
	// Mac 系统
	#define FILE_SEPERATOR '/' // 文件分割符
	#include <sys/stat.h>
	#include <dirent.h>
	#include <unistd.h>
#elif defined __linux__
	// Linux 操作系统
	#define FILE_SEPERATOR '/' // 文件分割符
	#include <sys/stat.h>
	#include <dirent.h>
	#include <unistd.h>
	#include <cstring>
#elif defined __unix || defined __unix__
	// Unix 操作系统
	#define FILE_SEPERATOR '/' // 文件分割符
	#include <sys/stat.h>
	#include <dirent.h>
	#include <unistd.h>
	#include <cstring>
#else
	#error Not support operator system!
#endif

namespace VL {

class VLFile {
public:
	// 文件类型
	using FileType=int;
	// 未知文件类型
	static const int FT_Unknown = 0;
	// 文件类型 - 文件
	static const int FT_File = 0x1;
	// 文件类型 - 文件夹
	static const int FT_Dir = 0x2;
	// 文件类型 - 链接
	static const int FT_Link = 0x4;

	/**
	 * @Author: CimZzz
	 * @Date: 2022-02-11 16:29:16
	 * 
	 * 构造函数, 当前所在目录
	 */
	explicit VLFile();

	/**
	 * @Author: CimZzz
	 * @Date: 2022-02-14 11:23:46
	 * 
	 * 构造函数, 指定文件夹下的路径
	 * 
	 * @param parent 父文件夹
	 * @param path 基于父文件夹下的路径
	 */
	explicit VLFile(const VLFile& parent, std::string path);

	/**
	 * @Author: CimZzz
	 * @Date: 2022-02-14 11:23:46
	 * 
	 * 构造函数, 指定文件夹下的路径
	 * 
	 * @param parent 父文件夹
	 * @param path 基于父文件夹下的路径
	 */
	explicit VLFile(VLFile* parent, std::string path);

	/**
	 * @Author: CimZzz
	 * @Date: 2022-02-14 11:23:46
	 * 
	 * 构造函数, 指定文件夹下的路径, 并替换后缀名
	 * 
	 * @param parent 父文件夹
	 * @param path 基于父文件夹下的路径
	 * @param ext 后缀名
	 */
	explicit VLFile(const VLFile& parent, std::string path, std::string ext);

	/**
	 * @Author: CimZzz
	 * @Date: 2022-02-11 16:31:04
	 * 
	 * 析构函数
	 */
	~VLFile();

	/**
	 * @Author: CimZzz
	 * @Date: 2022-02-11 16:31:12
	 * 
	 * 获取当前文件的绝对路径
	 * 
	 * @return 返回当前文件的绝对路径
	 */
	std::string getAbsolutePath() const;

	/**
	 * @Author: CimZzz
	 * @Date: 2022-08-19 16:57:11
	 * 
	 * 获取当前文件的绝对路径
	 * 
	 * @return 返回当前文件的绝对路径字符串形式
	 */
	inline const char * getAbsolutePathStr() const {
		return this->absolutePath.c_str();
	}

	/**
	 * @Author: CimZzz
	 * @Date: 2022-02-14 10:51:45
	 * 
	 * 获取当前文件名
	 * @return 返回当前文件名
	 */
	std::string getFileName();

	/**
	 * @Author: CimZzz
	 * @Date: 2022-02-18 11:42:40
	 * 
	 * 获取文件无后缀名
	 * @return 无后缀文件名
	 */
	std::string getBaseName();

	/**
	 * @Author: CimZzz
	 * @Date: 2022-02-18 11:43:07
	 * 
	 * 获取文件后缀名
	 * @return 文件后缀名
	 */
	std::string getExtName();

	/**
	 * @Author: CimZzz
	 * @Date: 2022-02-11 17:02:06
	 * 
	 * 通过路径检查文件类型
	 * @return 文件类型
	 */
	FileType getFileType();

	/**
	 * @Author: CimZzz
	 * @Date: 2022-02-14 11:08:57
	 * 
	 * 重命名文件到指定路径上
	 * @param filePath 文件路径
	 * 
	 * @return 重命名成功返回 true
	 */
	bool rename(std::string filePath);

	/**
	 * @Author: CimZzz
	 * @Date: 2022-02-14 11:10:02
	 * 
	 * 复制文件到指定路径上
	 * @param filePath 文件路径
	 * 
	 * @return 复制成功返回 true
	 */
	bool copy(std::string filePath);

	/**
	 * @Author: CimZzz
	 * @Date: 2022-02-11 17:09:30
	 * 
	 * 判断文件是否存在
	 * @return 如果存在返回 true
	 */
	bool isExist();

	/**
	 * @Author: CimZzz
	 * @Date: 2022-02-11 17:14:25
	 * 
	 * 判断当前路径是否指向文件
	 * 
	 * @return 如果是文件返回 true
	 */
	bool isFile();

	/**
	 * @Author: CimZzz
	 * @Date: 2022-02-11 17:15:15
	 * 
	 * 判断当前路径是否指向文件夹
	 * 
	 * @return 如果是文件夹返回 true
	 */
	bool isDirectory();

	/**
	 * @Author: CimZzz
	 * @Date: 2022-02-11 17:27:16
	 * 
	 * 获取文件夹下全部文件
	 * 
	 * @param fileType 指定文件类型
	 * 
	 * @return 文件列表
	 */
	const std::vector<std::shared_ptr<VLFile>> listFiles(FileType fileType = FT_Unknown);

	/**
	 * @Author: CimZzz
	 * @Date: 2022-02-18 16:54:34
	 * 
	 * 获取父文件夹路径
	 */
	std::string getParentPath() const &;

	/**
	 * @Author: CimZzz
	 * @Date: 2022-02-14 11:36:52
	 * 
	 * 获取文件夹
	 * @return 返回父级文件夹
	 */
	VLFile getParent() const &;

	/**
	 * @Author: CimZzz
	 * @Date: 2022-02-17 19:10:54
	 * 
	 * 更换后缀名
	 * @param ext 后缀名
	 * @return 更换过后缀名的文件
	 */
	VLFile replaceExt(std::string ext) const &;

	/**
	 * @Author: CimZzz
	 * @Date: 2022-02-21 17:07:34
	 * 
	 * 确保上级文件夹存在，如果不存在会尝试去创建新文件夹
	 * @return 上级文件夹存在返回 true
	 */
	bool makeSureParentDirExist();

	/**
	 * @Author: CimZzz
	 * @Date: 2022-02-15 16:00:19
	 * 
	 * 创建文件夹
	 * 
	 * @return 如果文件已存在并且文件类型不为文件夹, 或者创建失败返回 false
	 */
	bool newDir();

	/**
	 * @Author: CimZzz
	 * @Date: 2022-02-15 16:00:19
	 * 
	 * 创建文件
	 * 
	 * @return 如果文件已存在并且文件类型不为文件, 或者创建失败返回 false
	 */
	bool newFile();

	/**
	 * @Author: CimZzz
	 * @Date: 2022-02-16 16:01:41
	 * 
	 * 删除文件
	 * 
	 * @return 删除成功返回 true
	 */
	bool deleteFile();

	/**
	 * @Author: CimZzz
	 * @Date: 2022-02-16 16:53:16
	 * 
	 * 返回是否实际进行了创建/删除操作
	 * 
	 * @return 如果实际进行了上述操作返回 true
	 */
	bool isActionDone();

	/**
	 * @Author: CimZzz
	 * @Date: 2022-02-17 17:00:41
	 * 
	 * 获取文件最后的修改时间
	 * 
	 * @return 修改时间
	 */
	int64_t getModifyTime();

	/**
	 * @Author: CimZzz
	 * @Date: 2022-03-29 11:04:39
	 * 
	 * 获取别名路径
	 * 
	 * @return 别名路径
	 */
	std::string getAliasPath();
	
	/**
	 * @Author: CimZzz
	 * @Date: 2022-02-11 19:44:43
	 * 
	 * 获取用户根目录
	 * 
	 * @return 返回用户根目录
	 */
	static VLFile getUserProfileDir();

protected:
	/**
	 * @Author: CimZzz
	 * @Date: 2022-02-14 11:33:10
	 * 
	 * 初始化文件信息
	 * @param absolutePath 文件的绝对路径
	 */
	void initFileInfos(const std::string& absolutePath);

	/**
	 * @Author: CimZzz
	 * @Date: 2022-03-29 11:03:33
	 * 
	 * 相对路径, 目前之后在传入父文件夹的构造函数中才会记录该字段,
	 * 该字段表示第二个参数
	 */
	std::string aliasPath;

private:


	/**
	 * @Author: CimZzz
	 * @Date: 2022-02-11 16:38:19
	 * 
	 * 绝对路径
	 */
	std::string absolutePath;

	/**
	 * @Author: CimZzz
	 * @Date: 2022-02-14 10:49:07
	 * 
	 * 文件名
	 */
	std::string fileName;

	/**
	 * @Author: CimZzz
	 * @Date: 2022-02-17 19:08:23
	 * 
	 * 无后缀文件名
	 */
	std::string baseName;

	/**
	 * @Author: CimZzz
	 * @Date: 2022-02-18 11:42:12
	 * 
	 * 后缀名
	 */
	std::string extName;

	/**
	 * @Author: CimZzz
	 * @Date: 2022-02-16 16:52:30
	 * 
	 * 用来判断是否实际进行了 创建/删除 操作
	 */
	bool actionDone;
};

/**
 * @Author: CimZzz
 * @Date: 2022-08-03 17:26:30
 * 
 * 真实路径文件
 * 
 * 如果文件不存在, 则会立即抛出异常
 */
class VLRealPathFile: public VLFile {
public:
	/**
	 * @Author: CimZzz
	 * @Date: 2022-02-11 16:30:01
	 * 
	 * 构造函数, 指定文件路径
	 * 
	 * @param path 文件路径
	 */
	explicit VLRealPathFile(std::string path);

	/**
	 * @Author: CimZzz
	 * @Date: 2022-02-14 11:23:46
	 * 
	 * 构造函数, 指定文件夹下的路径
	 * 
	 * @param parent 父文件夹
	 * @param path 基于父文件夹下的路径
	 */
	explicit VLRealPathFile(const VLFile& parent, std::string path);
};

/**
 * @Author: CimZzz
 * @Date: 2022-08-03 17:26:56
 * 
 * 绝对路径文件
 */
class VLAbsolutePathFile: public VLFile {
public:
	/**
	 * @Author: CimZzz
	 * @Date: 2022-02-11 16:30:01
	 * 
	 * 构造函数, 指定文件路径
	 * 
	 * @param path 文件路径
	 */
	explicit VLAbsolutePathFile(std::string path);
};

} // namespace VL


#endif //VL_FILE__H_
